Part 3: 사용자 개인정보 데이터흐름
| 항목 | 내용 |
|---|---|
| 문서명 | Part 3: 사용자 개인정보 데이터흐름 |
| 제품명 | DTA Wide Sleep Management Platform |
| 작성일 | 2026-06-18 |
| 적용범위 | Part 3 (백엔드) — 사용자 개인·민감 데이터에 한정 |
| 관련 조항 | O.Purp_1/3/7, O.Data_1/2/3/5/6/7, O.Arch_2/5, O.TrdP_6/9/10, O.Ntwk_1 |
| 참조 표준 | BSI TR-03161, GDPR Art.30 (처리활동 기록) |
1. 목적 및 범위
본 문서는 DTA Wide 백엔드(dta-wide-api)에서 처리되는 사용자 개인·민감 데이터의 수집·처리·저장·전송·삭제 흐름을 정의한다. 본 문서는 여러 BSI 조항의 공통 증빙 자료로 사용된다(§0 매핑 참조).
범위 한정: 본 문서는 개인·민감 데이터만 다룬다. 비개인 운영 데이터(설정, 룩업 테이블, 로그 인프라 등)와 앱 전반 아키텍처는 대상이 아니다. 시스템 아키텍처는 p3_01_backend_infra_architecture, 클라우드 위탁 책임은 p3_04_cloud_outsourcing_responsibility, 암호 키 수명주기는 p3_05_cryptographic_key_lifecycle를 참조한다.
본 문서의 모든 사실 단정은 코드·스키마 앵커(파일:라인)로 뒷받침된다.
0. 본 문서가 커버하는 BSI 조항
| 섹션 | 커버 조항 |
|---|---|
| §2 개인데이터 인벤토리·분류 | O.Purp_1 (BSIA-238), O.Data_3 (314), O.Arch_2 (246) |
| §3 데이터 흐름 다이어그램 | O.Arch_2 (246), O.Ntwk_1 (327) |
| §4 라이프사이클 (수집→삭제) | O.Purp_3 (240), O.Data_2 (313), O.Data_7 (318) |
| §5 저장 맵 + at-rest 암호화 | O.Data_1 (312), O.Arch_4 (248) |
| §6 외부·서드파티 공유 매트릭스 | O.TrdP_6 (273), O.TrdP_9 (276), O.TrdP_10 (277), O.Purp_7 (244) |
| §7 인터페이스 보호·알림 | O.Arch_5 (249), O.Data_5 (316), O.Data_6 (317) |
2. 개인데이터 인벤토리 및 분류
백엔드가 처리하는 개인·민감 데이터 카테고리. 저장 위치는 PostgreSQL(Cloud SQL, private 스키마)을 기본으로 한다.
| 카테고리 | 데이터 항목 | 저장 위치 (앵커) | 분류 |
|---|---|---|---|
| 신원 — eID | eidHash (SHA-256, unique) | eid_links.eid_hash (private.prisma:247) | 가명화 |
| 신원 — eID | kvnr (보험번호, 영구 저장) | eid_links.kvnr VarChar(10) (private.prisma:248) | 민감 |
| 신원 — eID | metadata (sub·email·name [·insurer]) | eid_links.metadata Json (private.prisma:249) | 개인 |
| 신원 — eID | birthdate | 미저장·미사용 (DTO에만 존재) | — |
| 인증 | refresh/access token, app token, session | RefreshToken/AccessToken/AppToken/Session (private.prisma:162/182/220/198) | 비밀 |
| 인증 — 2FA | 디바이스 공개키 (ECC P-256 SPKI) | user_device_authentications.public_key_spki (private.prisma) | 공개키 |
| 동의 | 동의/철회 이력, IP, 무결성 HMAC | user_agreementments (private.prisma:307-329) | 개인 |
| 사용 이력 | userId, IP, User-Agent, 사용시각 | UsageHistory (private.prisma) | 개인 |
| 건강데이터 | 수면 로그·설문 응답 (가공본) | Firestore (agent-data 리포지토리) | 민감 |
eID 속성 저장 사실(정정 반영): eID 프로필 속성은 일시 폐기되지 않고
eid_links.metadata(Json)에 저장된다. 저장 필드는 쓰기 경로에 따라 다르다 — 신규 가입(eu-signup-orchestrator.service.ts:270-273)은sub·email·name을, 링크 완료(complete-eid-link.handler.ts:104-110)는 여기에insurer를 더해 저장한다.kvnr는 ePA 재인증 방지를 위해 영구 저장되며(스키마 주석, plan 177 agenda-001), 사용 시 마스킹된다(Kvnr.masked()—kvnr.vo.ts:28).birthdate는 DTO에 존재하나 저장·사용되지 않는다(코호트는 access-code/OAuth state로 결정).
3. 데이터 흐름 다이어그램
개인데이터의 수집 → 저장 → (제한적) 외부 흐름을 신뢰경계와 함께 표시한다. 굵은 화살표(①)는 인입 수집, 점선(④)은 비활성(전송 없음) 경로다.
흐름 요약: ① 앱이 개인데이터를 TLS로 전송하면 API가 입력검증(ValidationPipe) 후, ② 카테고리별로 신뢰경계(GCP·EU) 내부에 저장한다(at-rest 암호화 — §5). 신뢰경계를 넘는 개인·민감 데이터 흐름은 ③ gematik과의 eID 본인확인 OAuth 핸드셰이크뿐이며 여기에 건강데이터·KVNR은 실리지 않는다. ④ KVNR의 유일한 외부 전송 경로(ePA)는 현재 stub이라 실 전송이 없다(§6 참조). 모든 인입 통신은 TLS로 암호화된다(O.Ntwk_1, p3_05/177-cryptography-justification).
4. 라이프사이클 (수집 → 처리 → 저장 → 전송 → 삭제)
| 단계 | 처리 내용 | 통제 / 앵커 |
|---|---|---|
| 수집 | 인입 데이터는 전역 ValidationPipe(whitelist:true)로 검증, 미선언 필드 strip | main.ts:641-667 (O.Source_1 / BSIA-257) |
| 처리 | 목적 기반 최소화. KVNR 등 식별자는 마스킹 후 로깅 | kvnr.vo.ts:28, 로거 마스킹 (177-data-purpose-mapping) |
| 저장 | 카테고리별 저장소(§5). 민감 토큰·파일 URL은 필드 암호화 | auth.prisma:95, private.prisma:2082/2203 |
| 전송 | 외부 전송은 §6 매트릭스에 한정. 건강데이터·KVNR의 외부 라이브 전송 없음 | §6 |
| 삭제 | 계정 해지 시 eID 링크 삭제(eidLink.deleteMany), 2FA 디바이스 키는 Cascade 삭제 | private.prisma (UserDeviceAuthentication onDelete: Cascade) |
보존·삭제 정책 상세는
177-data-retention-policy(O.Data_2/_7) 참조.
5. 저장 맵 및 at-rest 암호화
| 저장소 | 저장 개인데이터 | at-rest 암호화 |
|---|---|---|
| PostgreSQL (Cloud SQL) | 신원(eID)·인증·동의·사용 이력 | GCP 기본 저장 암호화(플랫폼) + 민감 필드 애플리케이션 암호화 |
| Firestore | 가공 수면·설문 등 건강데이터 | GCP 기본 저장 암호화(플랫폼) |
| Redis (Memorystore) | 세션·캐시 (단기) | GCP 기본 저장 암호화(플랫폼) |
애플리케이션 레벨 필드 암호화(코드 확인):
refresh_token_cipher— 외부 IdP refresh token 암호화 저장 (auth.prisma:95)file_url_cipher— 파일 URL 암호화 (private.prisma:2203)encryption_key_id— 키 식별자 컬럼 (private.prisma:2082, 위와 별개 모델)
플랫폼 저장 암호화 및 키 관리 상세는 p3_05_cryptographic_key_lifecycle, 177-cryptography-justification을 참조한다.
6. 외부·서드파티 공유 매트릭스
백엔드가 개인데이터를 외부로 전송하는 경로 전체. (O.TrdP_6/9/10, O.Purp_7)
| 수신 대상 | 전송 데이터 | 목적 | 보호 수단 | 비고 |
|---|---|---|---|---|
| gematik eID IdP | OAuth 인증 핸드셰이크 | eID 본인확인 | TLS + OAuth/PKCE | 건강데이터 미전송 |
| ePA export | (KVNR — 미전송) | ePA 연동 (구현 중) | — | 현재 stub 어댑터만 바인딩 — 라이브 전송 없음 (epa-export-stub.adapter.ts:16-25, 바인딩 feature-health-data-export.module.ts:103-104) |
| GCP 서브프로세서 | §5의 저장 데이터 | 호스팅·저장·메시징 | DPA + 리전 고정(EU) | Cloud SQL/Firestore/Redis/Pub-Sub/BigQuery (p3_04) |
O.TrdP_6 (민감데이터 미전송): 건강데이터는 GCP 서브프로세서(저장 목적, DPA 하)를 제외하고 제3자에 전송되지 않는다. KVNR의 유일한 외부 egress 경로는 ePA export이나, 2026-06-18 기준 ePA 연동은 구현 중이며 운영에 바인딩된 유일 구현체는 stub 어댑터(
EpaExportStubAdapter)다. stub은EpaExportPort.send호출 시 실제 전송 없이 경고 로그만 남기고{ accepted: true, referenceId: 'stub' }를 반환하며, KVNR은 로그에 남기지 않는다(epa-export-stub.adapter.ts:16-25). 도메인 핸들러의epaPort.send(...)호출(epa-export.handler.ts:158)은 DI 바인딩(feature-health-data-export.module.ts:103-104)에 따라 이 stub으로 귀결되므로, 호출 코드만으로는 라이브 전송으로 오해될 수 있으나 실 전송은 없다. TIC/Konnektor 인프라 준비 후 라이브 어댑터 교체 예정. O.TrdP_9 (외부서비스 고지): GCP 서브프로세서 및 데이터 공유 내역은 클라우드 위탁 문서(p3_04) 및 개인정보처리방침에 고지된다(사용자 대면 고지 화면은 P.1-Mobile/landing 범위).
7. 인터페이스 보호 및 알림
- 인터페이스 보호 (O.Arch_5 / O.TrdP_10): 외부 서비스와의 모든 인터페이스는 TLS 암호화 + 인증/인가(스코프) + 입력 검증을 적용한다. 인입 검증은 §4(수집), 통신 암호화는
O.Ntwk_1(p3_05/177-cryptography-justification)을 따른다. - 데이터 export 통제 (O.Data_5): KVNR·건강데이터의 원천 외 반출은 §6 매트릭스에 한정되며, 그 외 export 경로는 존재하지 않는다.
- 알림 페이로드 (O.Data_6): 식별자(KVNR 등)는 사용 시 마스킹된다(
Kvnr.masked()—kvnr.vo.ts:28). 알림/푸시 페이로드의 민감정보 배제는 O.Data_6 통제 항목으로 별도 관리한다.
부록: 근거 코드 앵커
| 사실 | 앵커 |
|---|---|
| eID 속성 metadata 저장 | complete-eid-link.handler.ts:104-110 |
| eID 링크 모델/KVNR 영구저장 | private.prisma:244-263 |
| 동의/철회 이력 + 무결성 HMAC | private.prisma:307-329 |
| KVNR 마스킹 | kvnr.vo.ts:28 |
| ePA egress = stub (실 전송 없음) | epa-export-stub.adapter.ts:16-25 + 바인딩 feature-health-data-export.module.ts:103-104 (호출부 epa-export.handler.ts:158) |
| 인입 검증 (ValidationPipe) | main.ts:641-667 |
| 필드 암호화 — refresh token | auth.prisma:95 (refresh_token_cipher) |
| 필드 암호화 — 파일 URL | private.prisma:2203 (file_url_cipher), 키 식별자 private.prisma:2082 (encryption_key_id, 별개 모델) |